home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
utils
/
exec33a.arj
/
EXEC.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-06-22
|
36KB
|
1,182 lines
Unit exec;
{ --- Version 3.3 93-06-22 14:45 ---
EXEC.PAS: EXEC function with memory swap - prepare parameters.
Needs Assembler file 'spawn.asm' (assembled as 'spawnp.obj')
and unit 'checkpat'.
Public domain software by
Thomas Wagner
Ferrari electronic GmbH
Beusselstrasse 27
D-1000 Berlin 21
West Germany
BIXname: twagner
}
Interface
Uses
Dos, checkpat;
const
{e Return codes (only upper byte significant) }
{d Fehlercodes (nur das obere Byte signifikant) }
RC_PREPERR = $0100;
RC_NOFILE = $0200;
RC_EXECERR = $0300;
RC_ENVERR = $0400;
RC_SWAPERR = $0500;
RC_REDIRERR = $0600;
{e Swap method and option flags }
{d Auslagerungsmethoden ond Optionen }
USE_EMS = $01;
USE_XMS = $02;
USE_FILE = $04;
EMS_FIRST = $00;
XMS_FIRST = $10;
HIDE_FILE = $40;
NO_PREALLOC = $100;
CHECK_NET = $200;
USE_ALL = USE_EMS or USE_XMS or USE_FILE or CHECK_NET;
type
filename = string [81];
string128 = string [128];
pstring = ^string;
function do_exec (xfn: string; pars: string; spawn: integer;
needed: word; newenv: boolean): integer;
{>e
The EXEC function.
Parameters:
xfn is a string containing the name of the file
to be executed. If the string is empty,
the COMSPEC environment variable is used to
load a copy of COMMAND.COM or its equivalent.
If the filename does not include a path, the
current PATH is searched after the default.
If the filename does not include an extension,
the path is scanned for a COM, EXE, or BAT file
in that order.
pars The program parameters.
spawn If 0, the function will terminate after the
EXECed program returns, the function will not return.
NOTE: If the program file is not found, the function
will always return with the appropriate error
code, even if 'spawn' is 0.
If non-0, the function will return after executing the
program. If necessary (see the "needed" parameter),
memory will be swapped out before executing the program.
For swapping, spawn must contain a combination of the
following flags:
USE_EMS ($01) - allow EMS swap
USE_XMS ($02) - allow XMS swap
USE_FILE ($04) - allow File swap
The order of trying the different swap methods can be
controlled with one of the flags
EMS_FIRST ($00) - EMS, XMS, File (default)
XMS_FIRST ($10) - XMS, EMS, File
If swapping is to File, the attribute of the swap file
can be set to "hidden", so users are not irritated by
strange files appearing out of nowhere with the flag
HIDE_FILE ($40) - create swap file as hidden
and the behaviour on Network drives can be changed with
NO_PREALLOC (0x100) - don't preallocate
CHECK_NET (0x200) - don't preallocate if file on net.
This checking for Network is mainly to compensate for
a strange slowdown on Novell networks when preallocating
a file. You can either set NO_PREALLOC to avoid allocation
in any case, or let the prep_swap routine decide whether
to do preallocation or not depending on the file being
on a network drive (this will only work with DOS 3.1 or
later).
needed The memory needed for the program in paragraphs (16 Bytes).
If not enough memory is free, the program will
be swapped out.
Use 0 to never swap, $ffff to always swap.
If 'spawn' is 0, this parameter is irrelevant.
newenv If this parameter is FALSE, the environment
of the spawned program is a copy of the parent's
environment. If it is TRUE, a new environment
is created which includes the modifications from
previous 'putenv' calls.
Return value:
$0000..00FF: The EXECed Program's return code
$0101: Error preparing for swap: no space for swapping
$0102: Error preparing for swap: program too low in memory
$0200: Program file not found
$0201: Program file: Invalid drive
$0202: Program file: Invalid path
$0203: Program file: Invalid name
$0204: Program file: Invalid drive letter
$0205: Program file: Path too long
$0206: Program file: Drive not ready
$0207: Batchfile/COMMAND: COMMAND.COM not found
$0208: Error allocating temporary buffer
$03xx: DOS-error-code xx calling EXEC
$0400: Error allocating environment buffer
$0500: Swapping requested, but prep_swap has not
been called or returned an error.
$0501: MCBs don't match expected setup
$0502: Error while swapping out
$0600: Redirection syntax error
$06xx: DOS error xx on redirection
<}
{>d
Die EXEC Funktion.
Parameter:
xfn ist ein String mit dem Namen der auszuführenden Datei.
Ist der String leer, wird die COMSPEC Umgebungsvariable
benutzt um COMMAND.COM oder das Equivalent zu laden.
Ist kein Pfad angegeben, wird nach dem aktuellen Pfad
der in der PATH Umgebungsvariablen angegebene Pfad
durchsucht.
Ist kein Dateityp angegeben, wird der Pfad nach
einer COM oder EXE Datei (in dieser Reihenfolge) abgesucht.
pars Die Kommandozeile
spawn Wenn 0, wird der Programmlauf beendet wenn das
aufgerufene Programm zurückkehrt, die Funktion kehrt
nicht zurück.
HINWEIS: Wenn die auszuführende Datei nicht gefunden
wird, kehrt die Funktion mit einem Fehlercode
zurück, auch wenn der 'spawn' Parameter 0 ist.
Wenn nicht 0, kehrt die Funktion nach Ausführung des
Programms zurück. Falls notwendig (siehe den Parameter
"needed") wird der Programmspeicherbereich vor Aufruf
ausgelagert.
Zur Auslagerung muß der Parameter eine Kombination der
folgenden Flags enthalten:
USE_EMS ($01) - Auslagerung auf EMS zulassen
USE_XMS ($02) - Auslagerung auf XMS zulassen
USE_FILE ($04) - Auslagerung auf Datei zulassen
Die Reihenfolge der Versuche, auf die verschiedenen
Medien auszulagern kann mit einem der folgenden
Flags beeinflußt werden:
EMS_FIRST ($00) - EMS, XMS, Datei (Standard)
XMS_FIRST ($10) - XMS, EMS, Datei
Wenn die Auslagerung auf Datei erfolgt, kann das
Attribut dieser Datei auf "hidden" gesetzt werden,
damit der Benutzer nicht durch unversehends auftauchende
Dateien verwirrt wird:
HIDE_FILE ($40) - Auslagerungsdatei "hidden" erzeugen
Außerdem kann das Verhalten auf Netzwerk-Laufwerken
beeinflußt werden mit
NO_PREALLOC (0x100) - nicht Präallozieren
CHECK_NET (0x200) - nicht Präallozieren wenn Netz.
Diese Prüfung auf Netzwerk ist hauptsächlich sinnvoll
für Novell Netze, bei denen eine Präallozierung eine
erhebliche Verzögerung bewirkt. Sie können entweder mit
NO_PREALLOC eine Präallozierung in jedem Fall ausschließen,
oder die Entscheidung mit CHECK_NET prep_swap überlassen.
In diesem Fall wird nicht präalloziert wenn die Datei
auf einem Netzwerk-Laufwerk liegt (funktioniert nur
mit DOS Version 3.1 und späteren).
needed Der zur Ausführung des Programms benötigte Speicher
in Paragraphen (16 Bytes). Wenn nicht ausreichend
freier Speicher vorhanden ist, wird der Programm-
speicherbereich ausgelagert.
Bei Angabe von 0 wird nie ausgelagert, bei Angabe
von $ffff wird immer ausgelagert.
Ist der Parameter 'spawn' 0, hat 'needed' keine Bedeutung.
newenv Bestimmt die dem gerufenen Programm zu übergebenden
Umgebungsvariablen. Ist der Parameter FALSE,
wird eine Kopie der Vater-Umgebung benutzt,
d.h. daß Aufrufe von "putenv" keinen Effekt haben.
Ist er TRUE, wird eine neue Umgebung mit den
Modifikationen aus 'putenv' übergeben.
Liefert:
$0000..00FF: Rückgabewert des aufgerufenen Programms
$0101: Fehler bei Vorbereitung zum Auslagern -
kein Speicherplatz in XMS/EMS/Datei
$0102: Fehler bei Vorbereitung zum Auslagern -
der Programmcode ist zu nah am Beginn des
Programms.
$0200: Auszuführende Programmdatei nicht gefunden
$0201: Programmdatei: Ungültiges Laufwerk
$0202: Programmdatei: Ungültiger Pfad
$0203: Programmdatei: Ungültiger Dateiname
$0204: Programmdatei: Ungültiger Laufwerksbuchstabe
$0205: Programmdatei: Pfad zu lang
$0206: Programmdatei: Laufwerk nicht bereit
$0207: Batchfile/COMMAND: COMMAND.COM nicht gefunden
$0208: Fehler beim allozieren eines temporären Puffers
$03xx: DOS-Fehler-Code xx bei Aufruf von EXEC
$0400: Fehler beim allozieren der Umgebungsvariablenkopie
$0500: Auslagerung angefordert, aber prep_swap wurde nicht
aufgerufen oder lieferte einen Fehler
$0501: MCBs entsprechen nicht dem erwarteten Aufbau
$0502: Fehler beim Auslagern
$0600: Redirection Syntaxfehler
$06xx: DOS-Fehler xx bei Redirection
<}
{>e
The function pointed to by "spawn_check" will be called immediately
before doing the actual swap/exec, provided that
- the preparation code did not detect an error, and
- "spawn_check" is not NIL.
The function definition is
function name (cmdbat: integer; swapping: integer; var execfn: string;
var progpars: string): integer;
The parameters passed to this function are
cmdbat 1: Normal EXE/COM file
2: Executing BAT file via COMMAND.COM
3: Executing COMMAND.COM (or equivalent)
swapping < 0: Exec, don't swap
0: Spawn, don't swap
> 0: Spawn, swap
execfn the file name to execute (complete with path)
progpars the program parameter string
If the routine returns anything other than 0, the swap/exec will
not be executed, and do_exec will return with this code.
You can use this function to output messages (for example, the
usual "enter EXIT to return" message when loading COMMAND.COM)
and to do clean-up and additional checking.
CAUTION: If swapping is > 0, the routine may not modify the
memory layout, i.e. it may not call any memory allocation or
deallocation routines.
"spawn_check" is initialized to NIL.
<}
{>d
Die Funktion auf die "spawn_check" zeigt wird unmittelbar vor
Ausführung des Programmaufrufs aufgerufen, vorausgesetzt daß
- bei der Vorbereitung kein Fehler auftrat, und
- "spawn_check" nicht NIL ist.
Die Funktionsdefinition ist
function name (cmdbat: integer; swapping: integer; var execfn: string;
var progpars: string): integer;
Die der Funktion übergebenen Parameter sind
cmdbat 1: Normale EXE/COM Datei
2: Ausführung BAT Datei über COMMAND.COM
3: Ausführung COMMAND.COM (oder Equivalent)
swapping < 0: Exec, keine Auslagerung
0: Spawn, keine Auslagerung
> 0: Spawn, Auslagern
execfn Name und Pfad der auszuführenden Datei
progpars Programmparameter
Wenn die Routine einen Wert verschieden von 0 liefert, wird der
Programmaufruf nicht durchgeführt, und do_exec kehrt mit diesem
Wert zurück.
Sie können diese Funktion benutzen um Meldungen auszugeben
(zum Beispiel die übliche Meldung "Geben Sie EXIT ein um
zurückzukehren" bei Laden von COMMAND.COM), und für sonstige
Prüfungen oder Aufräumarbeiten.
ACHTUNG: Wenn swapping > 0 ist, darf die Funktion keinesfalls
den Speicheraufbau verändern, d.h. es dürfen keine Speicher-
Allozierungs oder -Deallozierungsroutinen benutzt werden.
"spawn_check" ist auf NIL initialisiert.
<}
type
spawn_check_proc = function (cmdbat: integer; swapping: integer;
var execfn: string; var progpars: string)
: integer;
var
spawn_check: spawn_check_proc;
{>e
The 'swap_prep' variable can be accessed from the spawn_check
call-back routine for additional information on the nature and
parameters of the swap. This variable will ONLY hold useful
information if the 'swapping' parameter to spawn_check is > 0.
The contents of this variable may not be changed.
The 'swapmethod' field will contain one of the flags USE_FILE,
USE_XMS, or USE_EMS.
Note that the 'swapfilename' field contains a zero-terminated string
with no prefixed length byte, not a Pascal string.
<}
{>d
Die Variable 'swap_prep' kann von der spawn_check Routine
benutzt werden um zusätzliche Informationen über Art und Parameter
der Auslagerung zu erfahren. Diese Variable enthält NUR DANN
sinnvolle Werte wenn der 'swapping' Parameter von spawn_check > 0 ist.
Der Inhalt dieser Variablen darf keinesfalls verändert werden.
Das Feld 'swapmethod' enthält einen der Werte USE_FILE,
USE_XMS, oder USE_EMS.
Bitte beachten Sie, daß das Feld 'swapfilename' einen Null-terminierten
String ohne Längenbyte, keinen Pascal-String, enthält.
<}
type
prep_block = record
xmm: longint; {e XMM entry address }
{d Einsprungadresse XMM }
first_mcb: integer; {e Segment of first MCB }
{d Segment des ersten MCB }
psp_mcb: integer; {e Segment of MCB of our PSP }
{d Segment des MCB unseres PSP }
env_mcb: integer; {e MCB of Environment segment }
{d MCB des Umgebungsvariablenblocks }
noswap_mcb: integer; {e MCB that may not be swapped }
{d MCB der nicht Ausgelagert wird }
ems_pageframe: integer; {e EMS page frame address }
{d EMS-Seiten-Adresse }
handle: integer; {e EMS/XMS/File handle }
{d Handle für EMS/XMS/Datei }
total_mcbs: integer; {e Total number of MCBs }
{d Gesamtzahl MCBs }
swapmethod: byte; {e Method for swapping }
{d Auslagerungsmethode }
swapfilename: array [0..80] of char;
{e Swap file name if swapping to file }
{d Auslagerungsdateiname }
end;
var
swap_prep: prep_block;
{ ------------------------------------------------------------------------- }
procedure putenv (envvar: string);
{ Adds a string to the environment. Note that the change to the
environment is valid for an exec'ed process only, and only if you
set the 'newenv' parameter in do_exec to TRUE. }
function envcount: integer;
function envstr (index: integer): string;
function getenv (envvar: string): string;
{ Replacement functions for the environment handling functions in the
DOS unit. All three functions work exactly like their DOS-unit
counterparts, except that they recognize the changes to the child
environment produced by 'putenv'. }
{===========================================================================}
Implementation
{>e
Define REDIRECT to support redirection.
CAUTION: The definition in 'spawn.asm' must match this definition!!
<}
{>d
Definieren Sie REDIRECT um Dateiumleitung zu untertützen.
ACHTUNG: Die Definition in 'spawn.asm' muß mit dieser Definition
übereinstimmen!!
<}
{$DEFINE REDIRECT}
const
swap_filename = '$$AAAAAA.AAA';
{e internal flags for prep_swap }
{d interne Flags für prep_swap }
CREAT_TEMP = $0080;
DONT_SWAP_ENV = $4000;
ERR_COMSPEC = -7;
ERR_NOMEM = -8;
spaces: set of #9..' ' = [#9, ' '];
type
stringptr = ^string;
stringarray = array [0..10000] of stringptr;
stringarrptr = ^stringarray;
bytearray = array [0..30000] of byte;
bytearrayptr = ^bytearray;
var
envptr: stringarrptr; { Pointer to the changed environment }
envcnt: integer; { Count of environment strings }
cmdpath: string;
cmdpars: string;
drive: string [3];
dir: string [67];
name: string [9];
ext: string [5];
{$L spawnp}
function do_spawn (swapping: integer;
var xeqfn; var cmdtail; envlen: word;
var env
{$IFDEF REDIRECT}
;stdin: pstring; stdout: pstring; stderr: pstring
{$ENDIF}
): integer; external;
function prep_swap (method: integer; var swapfn): integer; external;
{ helper routine }
function strpbrk (par, pattern: string): integer;
{ find position of any one of the characters in 'pattern' in string 'par' }
var
i: integer;
begin
for i := 1 to length (par) do
if pos (par [i], pattern) > 0
then begin
strpbrk := i;
exit;
end;
strpbrk := 0;
end;
{ Environment routines }
function envcount: integer;
{ Returns count of strings in environment. }
var
cnt: integer;
begin
if envptr = nil { If not yet changed }
then envcount := dos.envcount
else envcount := envcnt;
end;
function envstr (index: integer): string;
{ Returns environment string 'index' }
begin
if envptr = nil { If not yet changed }
then envstr := dos.envstr (index)
else if (index <= 0) or (index >= envcnt)
then envstr := ''
else if envptr^ [index - 1] = nil
then envstr := ''
else envstr := envptr^ [index - 1]^;
end;
function name_eq (var n1, n2: string): boolean;
{ Compares search string 'n1' with environment string 'n2'.
Case is insignificant. }
var
i: integer;
eq: boolean;
begin
i := 1;
eq := false;
while (i <= length (n1)) and (i <= length (n2)) and
(upcase (n1 [i]) = upcase (n2 [i])) do
i := i + 1;
name_eq := (i > length (n1)) and (i <= length (n2)) and (n2 [i] = '=');
end;
function searchenv (var str: string): integer;
{ Search for environment string, returns index in 'envptr' array.
Assumes 'envptr' is not NIL. }
var
idx: integer;
found: boolean;
begin
idx := 0;
found := false;
while (idx < envcnt) and not found do
begin
if envptr^ [idx] <> nil
then found := name_eq (str, envptr^ [idx]^);
idx := idx + 1;
end;
if not found
then searchenv := -1
else searchenv := idx - 1;
end;
function getenv (envvar: string): string;
{ Returns value of environment string specified by name. }
var
strp: stringptr;
eq: integer;
begin
if envptr = nil { If not yet changed }
then getenv := dos.getenv (envvar)
else begin
eq := searchenv (envvar);
if eq < 0
then getenv := ''
else begin
strp := envptr^ [eq];
eq := pos ('=', strp^);
getenv := copy (strp^, eq + 1, length (strp^) - eq);
end;
end;
end;
procedure init_envptr;
{ Initialise 'envptr' array. Called when 'putenv' is used for the
first time. Copies all environment strings into heap storage,
and builds an array of pointers to this strings. }
var
i: integer;
str: string [255];
begin
envcnt := dos.envcount;
getmem (envptr, envcnt * sizeof (stringptr));
if envptr = nil
then exit;
for i := 0 to envcnt - 1 do
begin
str := dos.envstr (i + 1);
getmem (envptr^ [i], length (str) + 1);
if envptr^ [i] <> nil
then envptr^ [i]^ := str;
end;
end;
procedure putenv (envvar: string);
{ Adds the string 'envvar' to the environment, or changes the
environment string if the name is already present. }
var
idx, eq: integer;
help: stringarrptr;
tmpvar : string;
begin
if envptr = nil
then init_envptr;
if envptr = nil
then exit;
eq := pos ('=', envvar);
if eq = 0
then exit;
for idx := 1 to eq do
envvar [idx] := upcase (envvar [idx]);
tmpvar := copy (envvar, 1, eq - 1); { Copy the portion up to "=" }
idx := searchenv (tmpvar);
if idx >= 0
then begin
freemem (envptr^ [idx], length (envptr^ [idx]^) + 1);
if eq >= length (envvar)
then envptr^ [idx] := nil
else begin
getmem (envptr^ [idx], length (envvar) + 1);
if envptr^ [idx] <> nil
then envptr^ [idx]^ := envvar;
end;
end
else if eq < length (envvar)
then begin
getmem (help, (envcnt + 1) * sizeof (stringptr));
if help = nil
then exit;
move (envptr^, help^, envcnt * sizeof (stringptr));
freemem (envptr, envcnt * sizeof (stringptr));
envptr := help;
getmem (envptr^ [envcnt], length (envvar) + 1);
if envptr^ [envcnt] <> nil
then envptr^ [envcnt]^ := envvar;
envcnt := envcnt + 1;
end;
end;
{ Routines to search for files }
function tryext (var fn: string): integer;
{ Try '.COM', '.EXE', and '.BAT' on current filename, modify filename if found. }
var
nfn: filename;
ok: boolean;
begin
tryext := 1;
nfn := fn + '.COM';
ok := exists (nfn);
if not ok
then begin
nfn := fn + '.EXE';
ok := exists (nfn);
end;
if not ok
then begin
tryext := 2;
nfn := fn + '.BAT';
ok := exists (nfn);
end;
if not ok
then tryext := 0
else fn := nfn;
end;
function findfile (var fn: string): integer;
{ Try to find the file 'fn' in the current path. Modifies the filename
accordingly. }
var
path: string;
i, j: integer;
hasext, found, check: integer;
begin
if fn = ''
then begin
if cmdpath = ''
then findfile := ERR_COMSPEC
else findfile := 3;
exit;
end;
check := checkpath (fn, INF_NODIR, drive, dir, name, ext, fn);
if check < 0
then begin
findfile := check;
exit;
end;
if ((check and HAS_WILD) <> 0) or ((check and HAS_FNAME) = 0)
then begin
findfile := ERR_FNAME;
exit;
end;
if (check and HAS_EXT) <> 0
then begin
for i := 1 to length (ext) do
ext [i] := upcase (ext [i]);
if ext = '.BAT'
then hasext := 2
else hasext := 1;
end
else hasext := 0;
if hasext <> 0
then begin
if (check and FILE_EXISTS) <> 0
then found := hasext
else found := 0;
end
else found := tryext (fn);
if (found <> 0) or ((check and (HAS_PATH or HAS_DRIVE)) <> 0)
then begin
findfile := found;
exit;
end;
path := getenv ('PATH');
i := 1;
while (found = 0) and (i <= length (path)) do
begin
j := 0;
while (path [i] <> ';') and (i <= length (path)) do
begin
j := j + 1;
fn [j] := path [i];
i := i + 1;
end;
i := i + 1;
if (j > 0)
then begin
if not (fn [j] in ['\', '/'])
then begin
j := j + 1;
fn [j] := '\';
end;
fn [0] := chr (j);
fn := fn + name + ext;
check := checkpath (fn, INF_NODIR, drive, dir, name, ext, fn);
if hasext <> 0
then begin
if (check and FILE_EXISTS) <> 0
then found := hasext
else found := 0;
end
else found := tryext (fn);
end;
end;
findfile := found;
end; { findfile }
{>e
Get name and path of the command processor via the COMSPEC
environmnt variable. Any parameters after the program name
are copied and inserted into the command line.
<}
{>d
Namen und Pfad des Kommandoprozessors über die COMSPEC-Umgebungs-
Variable bestimmen. Parameter nach dem Programmnamen werden kopiert
und in die Kommandozeile eingefügt.
<}
procedure getcmdpath;
var
i, found: integer;
begin
if length (cmdpath) > 0
then exit;
cmdpath := getenv ('COMSPEC');
cmdpars := '';
found := 0;
if cmdpath <> ''
then begin
i := 1;
while (i <= length (cmdpath)) and (cmdpath [i] in spaces) do
inc (i);
if i > 1
then begin
cmdpath := copy (cmdpath, i, 255);
i := 1;
end;
i := strpbrk (cmdpath, ';,=+/"[]|<> '#9);
if i <> 0
then begin
cmdpars := copy (cmdpath, i, 128);
cmdpath [0] := chr (i - 1);
i := 1;
while (i <= length (cmdpars)) and (cmdpars [i] in spaces) do
inc (i);
if i > 1
then cmdpars := copy (cmdpars, i, 128);
if cmdpars <> ''
then cmdpars := cmdpars + ' ';
end;
found := findfile (cmdpath);
end;
if found = 0
then begin
cmdpath := 'COMMAND.COM';
cmdpars := '';
found := findfile (cmdpath);
if found = 0
then cmdpath := '';
end;
end;
function tempdir (var outfn: filename): boolean;
{ Set temporary file path.
Read "TMP/TEMP" environment. If empty or invalid, clear path.
If TEMP is drive or drive+backslash only, return TEMP.
Otherwise check if given path is a valid directory.
}
var
stmp: array [0..3] of filename;
i, res: integer;
begin
stmp [0] := getenv ('TMP');
stmp [1] := getenv ('TEMP');
stmp [2] := '.\';
stmp [3] := '\';
for i := 0 to 3 do
if length (stmp [i]) <> 0
then begin
outfn := stmp [i];
res := checkpath (outfn, 0, drive, dir, name, ext, outfn);
if (res > 0) and ((res and IS_DIR) <> 0) and ((res and IS_READ_ONLY) = 0)
then begin
tempdir := true;
exit;
end;
end;
tempdir := false;
end;
{$IFDEF REDIRECT}
function parse_redirect (var par: string; idx: integer;
var stdin, stdout, stderr: pstring): boolean;
var
ch: char;
fnp: pstring;
fn: string;
app, i, beg, fne: integer;
begin
i := idx;
par [length (par) + 1] := #0;
repeat
app := 0;
ch := par [i];
beg := i;
i := i + 1;
if ch <> '<'
then begin
if par [i] = '&'
then begin
ch := '&';
inc (i);
end;
if par [i] = '>'
then begin
app := 1;
inc (i);
end;
end;
while (i <= length (par)) and (par [i] in spaces) do
inc (i);
fn := copy (par, i, 255);
fne := strpbrk (fn, ';,=+/"[]|<> '#9);
if fne = 0
then fne := length (fn) + 1;
par := copy (par, 1, beg - 1) + copy (fn, fne, 255);
i := beg;
fn [0] := chr (fne - 1);
if (fne = 0) or (length (fn) = 0)
then begin
parse_redirect := false;
exit;
end;
getmem (fnp, length (fn) + app + 2);
if fnp = NIL
then begin
parse_redirect := false;
exit;
end;
if app <> 0
then fnp^ := '>' + fn
else fnp^ := fn;
fnp^ [length (fnp^) + 1] := #0;
case ch of
'<': if stdin <> NIL
then begin
parse_redirect := false;
exit;
end
else stdin := fnp;
'>': if stdout <> NIL
then begin
parse_redirect := false;
exit;
end
else stdout := fnp;
'&': if stderr <> NIL
then begin
parse_redirect := false;
exit;
end
else stderr := fnp;
end;
i := strpbrk (fn, '<>');
until (i <= 0);
par [length (par) + 1] := #0;
parse_redirect := true;
end;
{$ENDIF}
function do_exec (xfn: string; pars: string; spawn: integer;
needed: word; newenv: boolean): integer;
label
exit;
var
cmdbat: integer;
swapfn: filename;
avail: word;
regs: registers;
envlen, einx: word;
idx, len, rc: integer;
envp: bytearrayptr;
swapping: integer;
{$IFDEF REDIRECT}
stdin, stdout, stderr: pstring;
{$ENDIF}
begin
{$IFDEF REDIRECT}
stdin := NIL; stdout := NIL; stderr := NIL;
{$ENDIF}
getcmdpath;
envlen := 0;
{ First, check if the file to execute exists. }
cmdbat := findfile (xfn);
if cmdbat <= 0
then begin
do_exec := RC_NOFILE or -cmdbat;
goto exit;
end;
if cmdbat > 1 { COMMAND.COM or Batch file }
then begin
if length (cmdpath) = 0
then begin
do_exec := RC_NOFILE or -ERR_COMSPEC;
goto exit;
end;
if cmdbat = 2
then pars := cmdpars + '/c ' + xfn + ' ' + pars
else pars := cmdpars + pars;
xfn := cmdpath;
end;
{$IFDEF REDIRECT}
idx := strpbrk (pars, '<>');
if idx > 0
then if not parse_redirect (pars, idx, stdin, stdout, stderr)
then begin
do_exec := RC_REDIRERR;
goto exit;
end;
{$ENDIF}
{ Now create a copy of the environment if the user wants it, and
if the environment has been changed. }
if newenv and (envptr <> nil)
then begin
for idx := 0 to envcnt - 1 do
envlen := envlen + length (envptr^ [idx]^) + 1;
if envlen > 0
then begin
envlen := envlen + 1;
getmem (envp, envlen);
if envp = nil
then begin
do_exec := RC_ENVERR;
goto exit;
end;
einx := 0;
for idx := 0 to envcnt - 1 do
begin
len := length (envptr^ [idx]^);
move (envptr^ [idx]^ [1], envp^ [einx], len);
envp^ [einx + len] := 0;
einx := einx + len + 1;
end;
envp^ [einx] := 0;
end;
end;
if spawn = 0
then swapping := -1
else begin
{ Determine amount of free memory }
with regs do
begin
ax := $4800;
bx := $ffff;
msdos (regs);
avail := regs.bx;
end;
{ No swapping if available memory > needed }
if needed < avail
then swapping := 0
else begin
{ Swapping necessary, use 'TMP' or 'TEMP' environment variable
to determine swap file path if defined. }
swapping := spawn;
if (spawn and USE_FILE) <> 0
then begin
if not tempdir (swapfn)
then begin
spawn := spawn xor USE_FILE;
swapping := spawn;
end
else begin
if (dosversion and $ff) >= 3
then swapping := swapping or CREAT_TEMP
else begin
swapfn := swapfn + swap_filename;
len := length (swapfn);
while exists (swapfn) do
begin
if (swapfn [len] >= 'Z')
then len := len - 1;
if (swapfn [len] = '.')
then len := len - 1;
swapfn [len] := succ (swapfn [len]);
end;
end;
swapfn [length (swapfn) + 1] := #0;
end;
end;
end;
end;
{ All set up, ready to go. }
if swapping > 0
then begin
if envlen = 0
then swapping := swapping or DONT_SWAP_ENV;
rc := prep_swap (swapping, swapfn);
if rc < 0
then begin
do_exec := RC_PREPERR or -rc;
goto exit;
end;
end;
xfn [length (xfn) + 1] := #0;
pars [length (pars) + 1] := #0;
if @spawn_check <> NIL
then begin
rc := spawn_check (cmdbat, swapping, xfn, pars);
if rc <> 0
then begin
do_exec := rc;
goto exit;
end;
end;
swapvectors;
{$IFDEF REDIRECT}
do_exec := do_spawn (swapping, xfn, pars, envlen, envp^, stdin, stdout, stderr);
{$ELSE}
do_exec := do_spawn (swapping, xfn, pars, envlen, envp^);
{$ENDIF}
swapvectors;
{ Free the environment buffer if it was allocated. }
exit:
if envlen > 0
then freemem (envp, envlen);
{$IFDEF REDIRECT}
if stdin <> NIL
then freemem (stdin, length (stdin^) + 2);
if stdout <> NIL
then freemem (stdout, length (stdout^) + 2);
if stderr <> NIL
then freemem (stderr, length (stderr^) + 2);
{$ENDIF}
end;
{ Initialisation for environment processing }
Begin
envptr := nil;
envcnt := 0;
cmdpath := '';
@spawn_check := nil;
End.